#include "spi_flash.h"

int flash_readID(int *spi_fd)
{
    int speed;
    //int mode;
    int bits;
    int delay;
    struct spi_ioc_transfer tr = {0};
    uint8_t tx_buf[] = {W25X_JEDECDEVICEID};
    uint8_t rx_buf[3] = {0, 0, 0};

    /*获取SPI速率*/
    if(ioctl(*spi_fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0){
        perror("Failed to get SPI speed");
        return -1;
    }

    /*获取字长*/
    if(ioctl(*spi_fd, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0){
        perror("Failed to get bits per word");
        return -1;
    }

    tr.tx_buf = (unsigned long)tx_buf;
    tr.rx_buf = (unsigned long)rx_buf;
    tr.len = 4;
    tr.delay_usecs = 0;
    tr.speed_hz = speed;
    tr.bits_per_word = bits;

    if(ioctl(*spi_fd, SPI_IOC_MESSAGE(1), &tr) < 0)
    {
        perror("Failed to read ID");
        return -1;
    }

    printf("Device ID = %02X %02X %02X %02X\n", rx_buf[0], rx_buf[1], rx_buf[2], rx_buf[3]);

    return 0;
}

int flash_write_enable(int *spi_fd)
{
    int speed;
    int bits;
    int delay;
    struct spi_ioc_transfer tr;
    uint8_t tx_buf[] = {W25X_WRITE_ENABLE};
    uint8_t rx_buf[] = {0};

    /*获取SPI速率*/
    if(ioctl(*spi_fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0){
        perror("Failed to get SPI speed");
        return -1;
    }

    /*获取字长*/
    if(ioctl(*spi_fd, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0){
        perror("Failed to get bits per word");
        return -1;
    }

    tr.tx_buf = (unsigned long)tx_buf;
    tr.rx_buf = (unsigned long)rx_buf;
    tr.len = sizeof(tx_buf);
    tr.delay_usecs = 0;
    tr.speed_hz = speed;
    tr.bits_per_word = bits;

    /*设置FLASH读取命令*/
    if(ioctl(*spi_fd, SPI_IOC_MESSAGE(1), &tr) < 0)
    {
        perror("Failed to enable write");
        return -1;
    }

    return 0;
}

int flash_write_disable(int *spi_fd)
{
    int speed;
    int bits;
    int delay;
    struct spi_ioc_transfer tr;
    uint8_t tx_buf[] = {W25X_WRITE_DISABLE};
    uint8_t rx_buf[] = {0};

    /*获取SPI速率*/
    if(ioctl(*spi_fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0){
        perror("Failed to get SPI speed");
        return -1;
    }

    /*获取字长*/
    if(ioctl(*spi_fd, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0){
        perror("Failed to get bits per word");
        return -1;
    }

    tr.tx_buf = (unsigned long)tx_buf;
    tr.rx_buf = (unsigned long)rx_buf;
    tr.len = sizeof(tx_buf);
    tr.delay_usecs = 0;
    tr.speed_hz = speed;
    tr.bits_per_word = bits;

    /*设置FLASH读取命令*/
    if(ioctl(*spi_fd, SPI_IOC_MESSAGE(1), &tr) < 1)
    {
        perror("Failed to disable write");
        return -1;
    }

    return 0;
}

int spi_flash_read(int *spi_fd, uint32_t address, uint8_t *buffer, size_t len)
{
    int speed;
    int bits;
    int delay;
    struct spi_ioc_transfer tr;
    uint8_t tx_buf[4];
    uint8_t rx_buf[4 + len];

    if (len % 4 != 0)
    {
        perror("Len must aligne 4 bytes\n");
        return -1;
    }

    if (address % 4 != 0)
    {
        perror("Address not aligne 4 byte \n");
        return -1;
    }

    /*获取SPI速率*/
    if(ioctl(*spi_fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0){
        perror("Failed to get SPI speed");
        return -1;
    }

    /*获取字长*/
    if(ioctl(*spi_fd, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0){
        perror("Failed to get bits per word");
        return -1;
    }

    tr.tx_buf = (unsigned long)tx_buf;
    tr.rx_buf = (unsigned long)rx_buf;
    tr.len = 4 + len;
    tr.delay_usecs = 0;
    tr.speed_hz = speed;
    tr.bits_per_word = bits;
    
    /*设置FLASH读取命令*/
    tx_buf[0] = W25X_READ_DATA;   //读取命令
    tx_buf[1] = (address >> 16) & 0xFF;
    tx_buf[2] = (address >> 8) & 0xFF;
    tx_buf[3] = address & 0xFF;

    /*清空接受缓冲区*/
    memset(&rx_buf[4], 0, len);
    if(ioctl(*spi_fd, SPI_IOC_MESSAGE(1), &tr) < 1)
    {
        perror("Failed to transfer SPI message");
        return -1;
    }

    /*复制到用户缓冲区*/
    memcpy(buffer, &rx_buf[4], len);

    return 0;
}
 
int spi_flash_write(int *spi_fd, uint32_t address, const uint8_t *data, size_t len)
{
    uint8_t tx_buf[4 + len];    //假设地址总线是32位
    int speed;
    //int mode;
    int bits;
    int delay;
    struct spi_ioc_transfer tr;

    if (len % 4 != 0)
    {
        perror("Len must aligne 4 bytes\n");
        return -1;
    }

    if (address % 4 != 0)
    {
        perror("Address not aligne 4 byte \n");
        return -1;
    }
    // /*获取模式*/
    // if(ioctl(*spi_fd, SPI_IOC_RD_MODE32, &mode) < 0){
    //     perror("Failed to get SPI mode");
    //     return -1;
    // }    

    /*获取SPI速率*/
    if(ioctl(*spi_fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0)
    {
        perror("Failed to get SPI speed");
        return -1;
    }

    /*获取字长*/
    if(ioctl(*spi_fd, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0){
        perror("Failed to get bits per word");
        return -1;
    }   

    tr.tx_buf = (unsigned long)tx_buf;
    tr.len = 4 + len;
    tr.delay_usecs = 0;
    tr.speed_hz = speed;
    tr.bits_per_word = bits;

    /*设置FLASH写命令*/
    tx_buf[0] = W25X_WRITE_PAGE;   //写命令
    tx_buf[1] = (address >> 16) & 0xFF;
    tx_buf[2] = (address >> 8) & 0xFF;
    tx_buf[3] = address & 0xFF;

    /*复制数据到缓冲区*/
    memcpy(&tx_buf[4], data, len);

    /*使能写寄存器*/
    if(flash_write_enable(spi_fd) < 0)
    {
        perror("Failed to execute flash_write_enable()");
        return -1;
    }

    /*执行写入操作*/
    if(ioctl(*spi_fd, SPI_IOC_MESSAGE(1), &tr) < 0)
    {
        perror("Failed to transfer SPI message");
        return -1;
    }

    return 0;
}

int spi_flash_erase_chip(int *spi_fd)
{
    int speed;
    int bits;
    int delay;
    struct spi_ioc_transfer tr = {0};
    uint8_t tx_buf[] = {W25X_CHIP_ERASE};

    /*获取SPI速率*/
    if(ioctl(*spi_fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0){
        perror("Failed to get SPI speed");
        return -1;
    }

    /*获取字长*/
    if(ioctl(*spi_fd, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0){
        perror("Failed to get bits per word");
        return -1;
    }

    tr.tx_buf = (unsigned long)tx_buf;
    tr.rx_buf = 0;
    tr.len = 1;
    tr.delay_usecs = 0;
    tr.speed_hz = speed;
    tr.bits_per_word = bits;

    if(flash_write_enable(spi_fd) < 0)
    {
        perror("Failed to execute flash_write_enable()");
        return -1;
    }

    if(ioctl(*spi_fd, SPI_IOC_MESSAGE(1), &tr) < 0)
    {
        perror("Failed to erase chip");
        return -1;
    }

    return 0;
}

int spi_flash_erase_sec(int *spi_fd, uint32_t address, uint32_t address_end)
{
    int speed;
    int bits;
    int delay;
    struct spi_ioc_transfer tr = {0};
    uint8_t tx_buf[4] = {W25X_SEC_ERASE, 0, 0, 0};

    if(address > address_end)
    {
        perror("Address_end can not more less than address_begin\n");
        return -1;
    }
    if ((address_end - address) % SIZE_4KB != 0)
    {
        perror("Len must aligne 4 Kbytes\n");
        return -1;
    }
    if (address % SIZE_4KB != 0)
    {
        perror("Address not aligne 4 Kbyte \n");
        return -1;
    }

    /*获取SPI速率*/
    if(ioctl(*spi_fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0){
        perror("Failed to get SPI speed");
        return -1;
    }

    /*获取字长*/
    if(ioctl(*spi_fd, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0){
        perror("Failed to get bits per word");
        return -1;
    }

    tr.tx_buf = (unsigned long)tx_buf;
    tr.rx_buf = 0;
    tr.len = 4;
    tr.delay_usecs = 0;
    tr.speed_hz = speed;
    tr.bits_per_word = bits;

    if(flash_write_enable(spi_fd) < 0)
    {
        perror("Failed to execute flash_write_enable()");
        return -1;
    }

    for(uint32_t addr = address; addr < address_end; addr += SIZE_4KB)
    {
        tx_buf[1] = (addr >> 16) & 0xFF;
        tx_buf[2] = (addr >> 8) & 0xFF;
        tx_buf[3] = (addr >> 0) & 0xFF;
        if(ioctl(*spi_fd, SPI_IOC_MESSAGE(1), &tr) < 0)
        {
            perror("Failed to erase chip");
            return -1;
        }
    }

    return 0;
}